/************************************************************
** @brief   : xbutton_test
** @author  : vandoul
** @github  : https://gitee.com/vandoul
** @date    : 2022-02
** @version : v1.0.0
** @note    : xbutton_test.c
***********************************************************/
#include <rtthread.h>
#include <rtdevice.h>
#include "xbutton.h"

static uint32_t xbutton_get_ms(void)
{
    return rt_tick_get_millisecond();
}
/* defined the BTN1 pin: PA4 */
#define BTN1_PIN    29
/* defined the BTN2 pin: PA5 */
#define BTN2_PIN    30
/* defined the BTN3 pin: PA6 */
#define BTN3_PIN    31
inline static rt_uint8_t read_btn1_level(void)
{
    return rt_pin_read(BTN1_PIN);
}
inline static rt_uint8_t read_btn2_level(void)
{
    return rt_pin_read(BTN2_PIN);
}
inline static rt_uint8_t read_btn3_level(void)
{
    return rt_pin_read(BTN3_PIN);
}
static rt_event_t btn_event;
static void btn_send_event(void *p)
{
    rt_event_send(btn_event, (uint32_t)p);
}
#define BTN1_EVENT_FLAG         (1<<0)
#define BTN2_EVENT_FLAG         (1<<1)
#define BTN3_EVENT_FLAG         (1<<2)
#define BTN_ALL_EVENT_FLAG      (BTN1_EVENT_FLAG|BTN2_EVENT_FLAG|BTN3_EVENT_FLAG)
static void btn_init(void)
{
    btn_event = rt_event_create("btn_evt", RT_IPC_FLAG_FIFO);
    if(btn_event == RT_NULL) {
        rt_kprintf("create btn event failed!\r\n");
        return ;
    }
    rt_pin_mode(BTN1_PIN, PIN_MODE_INPUT_PULLUP);
    rt_pin_mode(BTN2_PIN, PIN_MODE_INPUT_PULLUP);
    rt_pin_mode(BTN3_PIN, PIN_MODE_INPUT_PULLUP);
    rt_pin_attach_irq(BTN1_PIN, PIN_IRQ_MODE_RISING_FALLING, btn_send_event, (void *)BTN1_EVENT_FLAG);
    rt_pin_attach_irq(BTN2_PIN, PIN_IRQ_MODE_RISING_FALLING, btn_send_event, (void *)BTN2_EVENT_FLAG);
    rt_pin_attach_irq(BTN3_PIN, PIN_IRQ_MODE_RISING_FALLING, btn_send_event, (void *)BTN3_EVENT_FLAG);
    rt_pin_irq_enable(BTN1_PIN, PIN_IRQ_ENABLE);
    rt_pin_irq_enable(BTN2_PIN, PIN_IRQ_ENABLE);
    rt_pin_irq_enable(BTN3_PIN, PIN_IRQ_ENABLE);
}
static void button_event_callback(int index, xbutton_event_t evt)
{
    rt_kprintf("%d:%s!\r\n", index, xbutton_event_code_to_string(evt));
}
static int button_wait_event(int *level)
{
    uint32_t evt;
    int index = -1;
    if(rt_event_recv(btn_event, BTN_ALL_EVENT_FLAG, RT_EVENT_FLAG_OR, rt_tick_from_millisecond(50), &evt) == RT_EOK) {
        if(evt & BTN1_EVENT_FLAG) {
            rt_event_recv(btn_event, BTN1_EVENT_FLAG, RT_EVENT_FLAG_AND|RT_EVENT_FLAG_CLEAR, 0, RT_NULL);
            index = 0;
        } else if(evt & BTN2_EVENT_FLAG) {
            rt_event_recv(btn_event, BTN2_EVENT_FLAG, RT_EVENT_FLAG_AND|RT_EVENT_FLAG_CLEAR, 0, RT_NULL);
            index = 1;
        } else if(evt & BTN3_EVENT_FLAG) {
            rt_event_recv(btn_event, BTN3_EVENT_FLAG, RT_EVENT_FLAG_AND|RT_EVENT_FLAG_CLEAR, 0, RT_NULL);
            index = 2;
        } else {
            rt_event_recv(btn_event, BTN_ALL_EVENT_FLAG, RT_EVENT_FLAG_OR|RT_EVENT_FLAG_CLEAR, 0, RT_NULL);
            index = -1;
        }
    }
    if(level) {
        switch(index) {
        case 0: {
            *level = read_btn1_level();
        }
        break;
        case 1: {
            *level = read_btn2_level();
        }
        break;
        case 2: {
            *level = read_btn3_level();
        }
        break;
        default: {
            *level = -1;
        }
        break;
        }
    }
    return index;
}

void xbutton_test_task(void *param)
{
    rt_device_t cons = (rt_device_t)param;
    btn_init();
    xbutton_init(3, xbutton_get_ms, button_wait_event);
    xbutton_add(0, 0);
    xbutton_add(1, 0);
    xbutton_add(2, 0);
    xbutton_add_button_event(0, XBUTTON_DOWN, button_event_callback);
    xbutton_add_button_event(0, XBUTTON_DOUBLE, button_event_callback);
    xbutton_add_button_event(0, XBUTTON_LONG, button_event_callback);
    xbutton_add_button_event(1, XBUTTON_EVENT_ALL, button_event_callback);
    xbutton_add_button_event(2, XBUTTON_EVENT_ALL, button_event_callback);
    while(1) {
        char ch;
        xbutton_process();
        if((cons != RT_NULL) && rt_device_read(cons, -1, &ch, 1) == 1) {
            if(ch == 'q' || ch == 'Q' || ch == 0x03) {
                break;
            } else {
                rt_kprintf("%02x\r\n", ch);
            }
        }
    }
    xbutton_delete(0);
    xbutton_delete(1);
    xbutton_delete(2);
    xbutton_deinit();
}
static int xbutton_test(int argc, char *argv[])
{
    rt_device_t cons = rt_console_get_device();
    if(cons == RT_NULL) {
        rt_kprintf("get console failed!\r\n");
        return -1;
    }
    if((argc == 2) && !rt_strcmp(argv[1], "&")) {
        rt_thread_t tid;
        tid = rt_thread_create("xbtn", xbutton_test_task, RT_NULL, 1024, 10, 10);
        if(tid != RT_NULL) {
            rt_thread_startup(tid);
        }
    } else {
        xbutton_test_task(cons);
    }
    
    return 0;
}

MSH_CMD_EXPORT_ALIAS(xbutton_test, xbutton, test for xbutton.);
